package com.gitee.huanminabc.jcommon.multithreading;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 读写锁-根据key进行锁定。写在同一个key上的操作是互斥的，读在同一个key上的操作是并发的。
 * <p>
 * <b>功能说明：</b><br>
 * - 支持对任意字符串key进行读写锁隔离，适合分组并发场景。<br>
 * - 写锁互斥，读锁可并发，支持写锁降级为读锁。<br>
 * - 自动管理锁对象的生命周期，避免内存泄漏。<br>
 * - 线程安全，适合高并发环境。
 * <br>
 * <b>典型用法：</b>
 * <pre>
 *   SimpleLockReadWriteKey lock = new SimpleLockReadWriteKey();
 *   // 写操作
 *   lock.writeLock("user:123");
 *   try {
 *       // 执行写操作
 *   } finally {
 *       lock.unlock("user:123");
 *   }
 *   // 读操作
 *   lock.readLock("user:123");
 *   try {
 *       // 执行读操作
 *   } finally {
 *       lock.unlock("user:123");
 *   }
 * </pre>
 * <b>注意事项：</b><br>
 * - 每次加锁后必须配对调用 unlock，否则会导致死锁。<br>
 * - 支持同一线程重入。<br>
 * - 支持写锁降级为读锁（先持有写锁再加读锁，释放顺序反过来）。<br>
 * - 不支持跨线程解锁。
 *
 * @author huanmin
 * @date 2024/6/5 下午4:23
 */
public class SimpleLockReadWriteKey implements LockReadWriteKey<String>{
    private final Map<String, SimpleReadWriteLock> locks = new ConcurrentHashMap<>();
    
    // 用于清理的引用计数
    private final Map<String, AtomicInteger> refCounts = new ConcurrentHashMap<>();
    
    @Override
    public void readLock(String key) {
        if (key == null) {
            throw new IllegalArgumentException("key cannot be null");
        }
        SimpleReadWriteLock simpleReadWriteLock = getOrCreateLock(key);
        simpleReadWriteLock.readLock();
    }

    @Override
    public boolean readTryLock(String key) {
        if (key == null) {
            throw new IllegalArgumentException("key cannot be null");
        }
        SimpleReadWriteLock simpleReadWriteLock = getOrCreateLock(key);
        return simpleReadWriteLock.tryReadLock();
    }

    @Override
    public boolean readTryLock(String key, long timeout, TimeUnit unit) throws InterruptedException {
        if (key == null) {
            throw new IllegalArgumentException("key cannot be null");
        }
        SimpleReadWriteLock simpleReadWriteLock = getOrCreateLock(key);
        return simpleReadWriteLock.tryReadLock(timeout, unit);
    }

    @Override
    public void writeLock(String key) {
        if (key == null) {
            throw new IllegalArgumentException("key cannot be null");
        }
        SimpleReadWriteLock simpleReadWriteLock = getOrCreateLock(key);
        simpleReadWriteLock.writeLock();
    }

    @Override
    public boolean tryWriteLock(String key) {
        if (key == null) {
            throw new IllegalArgumentException("key cannot be null");
        }
        SimpleReadWriteLock simpleReadWriteLock = getOrCreateLock(key);
        return simpleReadWriteLock.tryWriteLock();
    }

    @Override
    public boolean tryWriteLock(String key, long timeout, TimeUnit unit) throws InterruptedException {
        if (key == null) {
            throw new IllegalArgumentException("key cannot be null");
        }
        SimpleReadWriteLock simpleReadWriteLock = getOrCreateLock(key);
        return simpleReadWriteLock.tryWriteLock(timeout, unit);
    }

    @Override
    public void unlock(String key) {
        if (key == null) {
            throw new IllegalArgumentException("key cannot be null");
        }
        SimpleReadWriteLock simpleReadWriteLock = locks.get(key);
        if (simpleReadWriteLock != null) {
            simpleReadWriteLock.unlock();
            // 减少引用计数
            decrementRefCount(key);
        }
    }
    
    /**
     * 获取或创建锁，同时增加引用计数
     */
    private SimpleReadWriteLock getOrCreateLock(String key) {
        AtomicInteger refCount = refCounts.computeIfAbsent(key, k -> new AtomicInteger(0));
        refCount.incrementAndGet();
        
        return locks.computeIfAbsent(key, k -> new SimpleReadWriteLock());
    }
    
    /**
     * 减少引用计数，如果计数为0则清理锁对象
     */
    private void decrementRefCount(String key) {
        AtomicInteger refCount = refCounts.get(key);
        if (refCount != null && refCount.decrementAndGet() <= 0) {
            // 引用计数为0，清理锁对象
            locks.remove(key);
            refCounts.remove(key);
        }
    }
    
    /**
     * 获取当前活跃的锁数量（用于调试和监控）
     */
    public int getActiveLockCount() {
        return locks.size();
    }
    
    /**
     * 强制清理所有锁（谨慎使用，仅用于测试或特殊情况）
     */
    public void clearAllLocks() {
        locks.clear();
        refCounts.clear();
    }
}
